import moment from 'moment';
import { FormItemProps } from './interface';
import { SelectProps } from './../select/interface';
import { parsingStr, eachStr } from './../../utils/replace/replace';
import { FormxControlTypes as FCT } from './data';
import { parse, stringify } from './../../utils/json/json';
import * as Pattern from './../../utils/pattern/pattern';

export const EXTRA_SESSION_KEY = 'formxExtra';
const DEFAULT_GROUP_NUM = 3;
const SPAN = 24;

const cache = {};
const requiredTrueObj = [{ required: true }];
const requiredFalseObj = [{ required: false }];

function getCacheKey(str: string, data: object) {
  let cacheKey: string[] = [];
  eachStr(str, (k: string) => cacheKey.push(`${k}=${data[k]}`));
  return cacheKey.join(',');
}

function strToEvalJS(str: string | boolean | undefined, data: object) {
  if (typeof str === 'boolean' || !str) return str;
  // eslint-disable-next-line
  return eval(parsingStr(str, data));
}

export function getDisabled(formItem: FormItemProps, data: object) {
  return strToEvalJS(formItem.disabled, data);
}

export function getRules(formItem: FormItemProps, data: object) {
  // if (formItem.rules) return formItem.rules;
  const defaultRule = { required: formItem.required };
  if (formItem.rules === 'letterNumbers') return [defaultRule, Pattern.letterNumbersPattern];
  if (formItem.rules === 'mail') return [defaultRule, Pattern.mailPattern];
  if (formItem.rules === 'phone') return [defaultRule, Pattern.phonePattern];
  if (formItem.rules === 'idNumber') return [defaultRule, Pattern.idNumberPattern];

  if (typeof formItem.required === 'boolean') return formItem.required ? requiredTrueObj : requiredFalseObj;

  if (typeof formItem.required === 'string') {
    const cacheKey = getCacheKey(formItem.required, data);
    const prevRulesCacheKey = (formItem as any)._prevRulesCacheKey;

    if (cacheKey !== prevRulesCacheKey) {
      (formItem as any)._prevRulesCacheKey = cacheKey;
      cache[cacheKey] = [{ required: strToEvalJS(formItem.required, data) }];
    }

    return cache[cacheKey];
  }
}

const PLEASE_SELECT_LOCAL_KEY = 'pleaseSelect';
const PLEASE_ENTER_LOCAL_KEY = 'pleaseEnter';

const prePromptMap = {
  [FCT.SELECT]: PLEASE_SELECT_LOCAL_KEY,
  [FCT.USER_INPUT]: PLEASE_SELECT_LOCAL_KEY,
  [FCT.CONSOLE_SELECT]: PLEASE_SELECT_LOCAL_KEY,
  [FCT.COMPANY_SELECT]: PLEASE_SELECT_LOCAL_KEY,
  [FCT.DATE]: PLEASE_SELECT_LOCAL_KEY
};

export function getPlaceholder(formItem: FormItemProps) {
  if (formItem.type === FCT.RANGE_PICKER) return '';
  if (formItem.placeholder) return formItem.placeholder;
  const before = window.$app.t(prePromptMap[formItem.type!] || PLEASE_ENTER_LOCAL_KEY);
  return before + (formItem.label || window.$app.t(formItem.name));
}

// 处理formItems ghost query 字符串
export function handleFormItemsParamStr(formItems: FormItemProps[], data: object) {
  let newFormItems: FormItemProps[] = [];

  formItems.forEach((item) => {
    let newItem = item, ghost = strToEvalJS(item.ghost, data);

    if (!ghost) {

      if ((item.type === FCT.SELECT || item.type === FCT.MODAL_TABLE) && (item.options as SelectProps).query) {
        const query = handleQueryStr(data, item);
        newItem = { ...item, options: { ...item.options, query } };
      }

      newFormItems.push(newItem);
    }
  });

  return newFormItems;
}

export function handleRowColStyle(groupNumber?: number) {
  if (groupNumber === 1) return { span: SPAN };

  const num = SPAN / (groupNumber || DEFAULT_GROUP_NUM);
  return { span: num };
}


export function handleInitialValues(initialValues: object, formItems: FormItemProps[]) {
  const newInitialValues = {};

  for (let k in initialValues) {

    const value = initialValues[k];
    const formItem = formItems.find(item => item.name === k);

    if (formItem?.type === FCT.DATE && value) {
      newInitialValues[k] = moment(value);
    } else if (formItem?.type === FCT.RANGE_PICKER && value) {
      newInitialValues[k] = value.map((item: string) => moment(item));
    } else {
      newInitialValues[k] = value;
    }
  }

  return newInitialValues;
}

function getSelectExtra(formItem: FormItemProps) {
  const options = formItem.options as SelectProps;
  const extra = typeof options.extra === 'string' ? parse(options.extra) : options.extra;
  if (extra && extra.length) return parse(sessionStorage[EXTRA_SESSION_KEY]);
  return {};
}

export function setExtra(extra: any) {
  sessionStorage[EXTRA_SESSION_KEY] = stringify(extra);
}

export function getExtraData(formItems: FormItemProps[], changedValues: object) {
  const currentName = Object.keys(changedValues)[0];
  const currentFormItem = formItems.find(({ name }) => name === currentName);

  if (currentFormItem?.options) {
    const type = currentFormItem.type as string;
    if (type === FCT.SELECT || type === FCT.CONSOLE_SELECT || type === FCT.COMPANY_SELECT || type === FCT.PRINT_TEMPLATE_SELECT) return getSelectExtra(currentFormItem);
    if (type === FCT.MODAL_TABLE || type === FCT.AUTO_COMPLETE || type === FCT.USER_INPUT) return parse(sessionStorage[EXTRA_SESSION_KEY]);
  }

  return {};
}

// 处理 validateFields 返回的 value
export function handleValues(formItems: FormItemProps[], values: object) {
  for (let name in values) {

    const currentFormItem = formItems.find(item => item.name === name);
    const value = values[name];

    if (value === undefined) values[name] = null;

    if (currentFormItem) {
      const type = currentFormItem.type as string;
      if ((type === FCT.CHECKBOX || type === FCT.SWITCH) && !value) values[name] = false;
      if (type === FCT.DATE && value) values[name] = moment(value).format(window.$app.MOMENT_FORMAT_TIME);
      if (type === FCT.RANGE_PICKER && value) values[name] = value.map((item: moment.MomentInput) => moment(item).format(window.$app.MOMENT_FORMAT_TIME));
    }

  }

  return values;
}

// 控件 extra配置的额外参数会直接以kv的形式挂载到formx formItemExtraData ref对象
// modalTableInModel由于支持多选kv比较特殊，其中k是以 '_' + 字段name，v则是数组
function getControlExtraKey(formItem: FormItemProps, curFormItem: FormItemProps) {
  if (curFormItem.type === FCT.MODAL_TABLE) return '_' + formItem.bindField;
  return formItem.bindField || formItem.name;
}

// 找出关联的formItems
function filterBindFormItems(formItems: FormItemProps[], name: string, extrasKey: string[]) {
  const filterFormItemsInCurBind = formItems.filter(item => {
    if (item.name === name) return false;
    return extrasKey.includes(item.bindField || item.name);
  });

  return filterFormItemsInCurBind;
}

// 处理input联动
function handleBindInputRelation(curExtraData: object, formItem: FormItemProps) {
  return typeof curExtraData === 'object' ? curExtraData[formItem.bindField || formItem.name] : curExtraData;
}

// 处理 query str
function handleQueryStr(allValues: object, formItem: FormItemProps) {

  const selectOptions = formItem.options;
  const query = selectOptions.query;

  // 需要把原始的query记录下来，否则第二次无法替换字段
  if (!(selectOptions as any)._query) (selectOptions as any)._query = selectOptions.query;

  if (!query || !Object.keys(query).length) return {};

  const _query = (selectOptions as any)._query;
  const replaceStr = parsingStr(typeof _query === 'string' ? _query : stringify(_query), allValues);

  eval(`window._replaceQuery = ${replaceStr}`);
  return (window as any)._replaceQuery;
}

// 处理联动关系
export function handleBindRelations(formItems: FormItemProps[], changedValues: object, allValues: object) {

  const extrasKey = Object.keys(changedValues); // 控件onChange时暴露出的数据
  const name = Object.keys(changedValues)[0];
  const formItemsInBindField = filterBindFormItems(formItems, name, extrasKey); // 找出关联的formItem
  const curFormItem = formItems.find(item => item.name === name);

  if (formItemsInBindField.length) {
    const fieldValues = {};

    formItemsInBindField.forEach(item => {
      const extraKey = getControlExtraKey(item, curFormItem!);
      const curExtraData = allValues[extraKey];

      if (!item.type || item.type === FCT.INPUT) {
        fieldValues[item.name] = handleBindInputRelation(curExtraData, item);

        if (curFormItem?.type === FCT.MODAL_TABLE) {
          fieldValues[item.name] = allValues[item.bindField!];
          delete allValues[item.bindField!];
        }
      }

      if (item.type === FCT.SELECT && item.options && (item.options as SelectProps).query) {
        fieldValues[item.name] = undefined;
      }

    });

    return fieldValues;
  }

  return {};
}

// 当 switch 关闭时，清空相关联ghost的表单值
export function diffFormItems(formItems: FormItemProps[], newFormItems: FormItemProps[], fieldsValue: object, extraData: object) {
  const formItemsMap = formItems.reduce((next, cur) => (next[cur.name] = true) && next, {});

  newFormItems.forEach(item => formItemsMap[item.name] = false);
  Object.keys(formItemsMap).forEach(item => {
    if (formItemsMap[item]) {
      delete fieldsValue[item];
      delete extraData[item];
    }
  });

}